// Tierless
// Copyright © 2010 Alphora
// This file is licensed under a modified BSD-license (see tierless_license.txt).

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

using Tierless.Framework.Utilities;

namespace Tierless.Framework.EntityTypes
{
	/// <summary>
	/// Represents the definition of an entity reference in an entity model.
	/// </summary>
	[DataContract]
	public class EntityReference : NamedEntityTypeObject
	{
		/// <summary>
		/// Initializes a new instance of the EntityReference class.
		/// </summary>
		/// <param name="name"></param>
		public EntityReference(string name)
			: base(name)
		{}

		private string _indexName;
		
		private string Unqualify(string name)
		{
			var lastIndex = name.LastIndexOf('.');
			return lastIndex >= 0 ? name.Substring(lastIndex + 1) : name;
		}

		/// <summary>
		/// Gets the name used to index the reference in lookup and child collections on an entity.
		/// </summary>
		public string IndexName
		{
			get
			{
				if (_indexName == null)
					_indexName = _kind == ReferenceKind.Child ? SourceEntityTypeName : SourceColumnNames.Combine();
				return _indexName;
			}
		}

		private string _propertyName;

		/// <summary>
		/// Gets the name of the property used to expose the reference on an entity.
		/// </summary>
		public string PropertyName
		{
			get
			{
				if (_propertyName == null)
				{
					if (_kind == ReferenceKind.Child)
						_propertyName = IndexName + "Collection";
					else
						_propertyName = IndexName + "Source";
				}
				return _propertyName;
			}
		}

		/// <summary>
		/// Gets or sets the title of the reference.
		/// </summary>
		[DataMember]
		public string Title { get; set; }

		private ReferenceKind _kind;

		/// <summary>
		/// Gets or sets the kind of reference, lookup or child.
		/// </summary>
		[DataMember]
		public ReferenceKind Kind
		{
			get { return _kind; }
			set { _kind = value; }
		}

		/// <summary>
		/// Gets or sets the name of the entity in which the reference originates.
		/// </summary>
		[DataMember]
		public string SourceEntityTypeName { get; set; }

		[DataMember]
		private EntityTypeColumnReferenceCollection _sourceColumns = new EntityTypeColumnReferenceCollection();

		/// <summary>
		/// Gets the set of columns in the source entity that form the referencing values.
		/// </summary>
		public EntityTypeColumnReferenceCollection SourceColumns
		{
			get { return _sourceColumns; }
		}

		/// <summary>
		/// Gets the names of the source reference columns as a string array.
		/// </summary>
		public string[] SourceColumnNames
		{
			get { return _sourceColumns.AsStringArray; }
			set { _sourceColumns.AsStringArray = value; }
		}

		/// <summary>
		/// Gets or sets the name of the entity which the reference targets.
		/// </summary>
		[DataMember]
		public string TargetEntityTypeName { get; set; }

		[DataMember]
		private EntityTypeColumnReferenceCollection _targetColumns = new EntityTypeColumnReferenceCollection();
	
		/// <summary>
		/// Gets the set of columns in the target entity that form the referenced values.
		/// </summary>
		public EntityTypeColumnReferenceCollection TargetColumns
		{
			get { return _targetColumns; }
		}

		/// <summary>
		/// Gets the names of the target reference columns as a string array.
		/// </summary>
		public string[] TargetColumnNames
		{
			get { return TargetColumns.AsStringArray; }
			set { TargetColumns.AsStringArray = value; }
		}

		private ReferentialAction _referentialAction = ReferentialAction.Require;

		/// <summary>
		/// Gets or sets the referential action used to enforce the reference automatically.
		/// </summary>
		public ReferentialAction ReferentialAction
		{
			get { return _referentialAction; }
			set { _referentialAction = value; }
		}

		/// <summary>
		/// Returns a string representation of the entity reference.
		/// </summary>
		/// <returns>A string representation of the entity reference.</returns>
		public override string ToString()
		{
			return
				String.Format
				(
					"EntityReference: Name={0}, Kind={1}, PropertyName={2}, SourceEntityTypeName={3}, SourceColumns={4}, TargetEntityTypeName={5}, TargetColumns={6}, Title={7};",
					Name,
					Enum.GetName(typeof (ReferenceKind), Kind),
					PropertyName,
					SourceEntityTypeName,
					SourceColumns,
					TargetEntityTypeName,
					TargetColumns,
					Title
				);
		}
	}
}